﻿using DotNet.Utilities.ConsoleHelper;
using PropertyChanged;
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using DotNet.Utilities;
using WPFPractice.Models;
using WPFPractice.Utils;
using WPFTemplateLib.WpfHelpers;
using System.Windows.Controls;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.Threading.Tasks;

namespace WPFPractice.Windows
{
    public partial class WinDataGrid2 : Window
    {
        private DataGrid2ViewModel _vm;

        public WinDataGrid2()
        {
            InitializeComponent();
            DataContext = _vm = new DataGrid2ViewModel();

            _vm.SelectedItemChanged += OnSelectedItemChanged;
        }

        /// <summary>
        /// 选中项改变事件执行方法
        /// </summary>
        /// <param name="index">选中行索引</param>
        private void OnSelectedItemChanged(int index)
        {
			try
			{
				if (index >= 0)
				{
					Dg.ScrollIntoView(Dg.Items.GetItemAt(index));
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show($"{ex}");
			}
        }

        private void EventSetter_LostFocus(object sender, RoutedEventArgs e)
        {
            var selected = _vm.SelectedItem;
            if(selected != null)
            {
                //selected.EditType = EditTypeEnum.Show;
            }
        }

        private void Dg_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            switch (sender)
            {
                //只在点击表格其它地方时执行某些操作，点击行时不处理;
                case DataGrid dg:
                    //想要进行的操作写这里;

                    MessageBox.Show("点击了表格空白处");

                    //如果是自动列，使用此方法可以使选中的单元格进入编辑模式，但是不知道如何使整行进入编辑模式;
                    dg.BeginEdit();

                    break;
                case DataGridRow row:
                    e.Handled = true; //标记为已处理，就不会触发之后的 DataGrid 的 MouseDown 事件;
                    break;
                default:
                    break;
            }
        }
    }

    [AddINotifyPropertyChangedInterface]
    public class DataGrid2ViewModel : MyBindableBase
    {
        #region 成员

        /// <summary>
        /// 改变前的对象引用
        /// </summary>
        private User _originUser;

        #endregion

        #region Bindable

        /// <summary>
        /// 表格数据
        /// </summary>
        public ObservableCollection<User> Datas { get; set; }

        /// <summary>
        /// 选中项改变事件
        /// </summary>
        public event Action<int> SelectedItemChanged;

        private User _SelectedItem;
        /// <summary>
        /// 选中项
        /// </summary>
        public User SelectedItem
        {
            get => _SelectedItem;
            set
            {
                SetProperty(ref _SelectedItem, value);

                SelectedItemChanged?.Invoke(Datas.IndexOf(_SelectedItem));
            }
        }

        private EditTypeEnum _editType = EditTypeEnum.Show;
        /// <summary>
        /// 编辑模式
        /// </summary>
        public EditTypeEnum EditType
        {
            get => _editType;
            set
            {
                _editType = value;
                ShowInfoUc($"切换到 {_editType.GetEnumDescription()}");
            }
        }

        /// <summary>
        /// 是否显示个性签名
        /// </summary>
        public bool IsShowSignature { get; set; } = true;

        /// <summary>
        /// 指定的选中索引
        /// </summary>
        public int SelectedNo { get; set; } = 1;

        #endregion

        #region Command

        /// <summary>
        /// 切换到新增模式命令
        /// </summary>
        public ICommand AddNewCmd { get; set; }

        /// <summary>
        /// 添加用户命令
        /// </summary>
        public ICommand AddUserCmd { get; set; }

        /// <summary>
        /// 表格选择行变化事件触发命令
        /// </summary>
        public ICommand SelectionChangedCmd { get; set; }

        /// <summary>
        /// 是否能执行选择行变化命令
        /// </summary>
        public bool IsCanSelectionChanged { get; set; } = true;

        /// <summary>
        /// 删除命令
        /// </summary>
        public ICommand DeleteCmd { get; set; }

        /// <summary>
        /// 显示隐藏个性签名命令
        /// </summary>
        public ICommand ShowOrHideSignCmd { get; set; }

        /// <summary>
        /// 进入编辑模式命令
        /// </summary>
        public ICommand EnterEditCmd { get; set; }

        /// <summary>
        /// 失去焦点事件命令
        /// </summary>
        public ICommand LostFocusCmd { get; set; }

        /// <summary>
        /// 选中指定序号条目的命令
        /// </summary>
        public ICommand SelectCmd { get; set; }

        #endregion

        public DataGrid2ViewModel()
        {
            Console.SetOut(new ConsoleWriter(s =>
            {
                ShowInfoUc(s);
            }));

            SetCommandMethod();

            InitValueTaskAsync();
        }

        /// <summary>
        /// 数据初始化
        /// </summary>
        private async Task InitValueTaskAsync()
        {
            await Task.Delay(200);
            ShowInfoUc("演示 DataGrid 行内编辑、滚动到选中项");
            ShowInfoUc("演示 属性变动后的业务处理及还原属性原始值（年龄大于200）");
            Datas = new ObservableCollection<User>()
            {
                new User(){UserId = "01", UserName = "张三", Gender = "男", Age = 20, MobileNum = "13597362875", Address = "浙江省杭州市西湖区古墩路", Signature = "好好学习，天天向上"},
                new User(){UserId = "02", UserName = "李四", Gender = "男", Age = 22, MobileNum = "13385937628", Address = "福建省南平市邵武市水北镇", Signature = "生命不息，奋斗不止"},
                new User(){UserId = "03", UserName = "王妩", Gender = "女", Age = 24, MobileNum = "17129463982", Address = "美利坚共和国加利福尼亚洲", Signature = "天妒英才，命运多舛"},
                new User(){UserId = "04", UserName = "赵溜", Gender = "男", Age = 28, MobileNum = "18868839476", Address = "火星基地一号华中区杭州堡", Signature = "人生一世，草木一秋"},
                new User(){UserId = "05", UserName = "钱七", Gender = "男", Age = 38, MobileNum = "18868839476", Address = "", Signature = ""},
                new User(){UserId = "06", UserName = "孙子", Gender = "男", Age = 08, MobileNum = "18868839476", Address = "", Signature = ""},
                new User(){UserId = "07", UserName = "李老", Gender = "男", Age = 48, MobileNum = "18868839476", Address = "", Signature = ""},
                new User(){UserId = "08", UserName = "魏王", Gender = "男", Age = 58, MobileNum = "18868839476", Address = "", Signature = ""},
                new User(){UserId = "09", UserName = "九九", Gender = "男", Age = 99, MobileNum = "18868839476", Address = "", Signature = ""},
                new User(){UserId = "10", UserName = "石海", Gender = "男", Age = 98, MobileNum = "18868839476", Address = "", Signature = ""},
            };
        }

        /// <summary>
        /// 命令方法赋值(在构造函数中调用)
        /// </summary>
        private void SetCommandMethod()
        {
            AddNewCmd ??= new RelayCommand(o => true, o =>
            {
                EditType = EditTypeEnum.Add;
                SelectedItem = new User();
            });

            AddUserCmd ??= new RelayCommand(o => !(string.IsNullOrEmpty(SelectedItem?.UserId) || string.IsNullOrEmpty(SelectedItem?.UserName)), o =>
            {
                Datas.Add(SelectedItem);
                ShowInfoUc($"已添加用户 {SelectedItem.UserId}");

                EditType = EditTypeEnum.Show;
            });

            SelectionChangedCmd ??= new RelayCommand(o => IsCanSelectionChanged, o =>
            {
                try
                {
                    IsCanSelectionChanged = false;

                    var args = o as SelectionChangedEventArgs;
                    EditType = EditTypeEnum.Show;

                    if (_originUser != null)
                    {
                        _originUser.EditType = EditTypeEnum.Show;

                        //演示属性变动后的业务处理(取消方法);
                        _originUser.PropertyChanged -= User_PropertyChanged;
                        _originUser.PropertyChanging -= User_PropertyChanging;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                finally
                {
                    _originUser = SelectedItem;  
                    IsCanSelectionChanged = true;
                }
            });

            DeleteCmd ??= new RelayCommand(o => true, o =>
            {
                var user = o as User;
                if(user == null)
                {
                    return;
                }

                Datas.Remove(user);
                ShowInfoUc($"已删除用户[{user.UserId}]");
                EditType = EditTypeEnum.Show;
            });

            ShowOrHideSignCmd ??= new RelayCommand(o => true, o =>
            {
                IsShowSignature = !IsShowSignature;
            });

            EnterEditCmd ??= new RelayCommand(o => true, o =>
            {
                EditType = EditTypeEnum.Edit;
                if (SelectedItem != null)
                {
                    SelectedItem.EditType = EditType;

                    //演示属性变动后的业务处理(附加方法);
                    SelectedItem.PropertyChanged += User_PropertyChanged;
                    SelectedItem.PropertyChanging += User_PropertyChanging;
                }
            });

            LostFocusCmd ??= new RelayCommand(o => true, o =>
            {
                var args = o as RoutedEventArgs;

                if (args.Source.GetType() == typeof(DataGrid) && SelectedItem != null)
                {
                    //SelectedItem.EditType = EditTypeEnum.Show;
                }
            });

            SelectCmd ??= new RelayCommand(o => true, o =>
            {
                try
                {
                    var selected = Datas[SelectedNo-1];
                    SelectedItem = selected;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"选择命令执行异常：{ex}");
                }
            });
        }

        #region 属性变动处理

        /// <summary>
        /// 属性变更中（记录原始值）
        /// </summary>
        private void User_PropertyChanging(object sender, PropertyChangingEventArgs e)
        {
            Type type = sender.GetType();
            PropertyInfo propertyInfo = type.GetProperty(e.PropertyName);
            if (propertyInfo != null)
            {
                _originPropertyValueDict[e.PropertyName] = propertyInfo.GetValue(sender);
            }
        }

        /// <summary>
        /// 原始的属性值字典
        /// </summary>
        private Dictionary<string, object> _originPropertyValueDict = new Dictionary<string, object>();

        /// <summary>
        /// 正在被还原的属性名列表
        /// </summary>
        private List<string> _revertPropertyList = new List<string>();

        /// <summary>
        /// 属性变更后（业务处理）
        /// </summary>
        private void User_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            try
            {
                //如果属性存在于忽略列表中，则从忽略列表中移除，并跳过此次执行（业务处理）
                if (_revertPropertyList.Contains(e.PropertyName))
                {
                    _revertPropertyList.Remove(e.PropertyName);
                    return;
                }

                bool isSuccess = true; //业务处理是否成功;
                var defaultObject = default(User); //只是用于获取属性名称;

                try
                {
                    //业务处理;
                    switch (e.PropertyName)
                    {
                        case nameof(defaultObject.UserName):
                        {
                            ToastToScreenCmd.Execute($"用户名设置成功：{SelectedItem.UserName}"); //模拟业务处理;
                            break;
                        }
                        case nameof(defaultObject.Age):
                        {
                            //模拟还原属性原始值;
                            if (SelectedItem.Age > 200)
                            {
                                isSuccess = false;
                                ToastToScreenCmd.Execute("人不可能这么大年龄，请重新设置!");
                            }
                            break;
                        }
                        default:
                        {
                            //isSuccess = false;
                            //ToastToScreenCmd.Execute("无对应项");
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    isSuccess = false;
                    Console.WriteLine($"异常：{ex}");
                }

                if (isSuccess)
                {
                    ToastToScreenCmd.Execute("设置完成");
                }
                else //不成功则还原值
                {
                    //添加到忽略列表，避免循环;
                    _revertPropertyList.Add(e.PropertyName);

                    //还原原始值
                    Type type = sender.GetType();
                    PropertyInfo propertyInfo = type.GetProperty(e.PropertyName);
                    if (propertyInfo != null)
                    {
                        propertyInfo.SetValue(sender, _originPropertyValueDict[e.PropertyName], null);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"异常：{ex}");
            }
        }

        #endregion
    }
}
